// Copyright  2004-2008 Backplane Ltd.
//
// This file is part of Ubiquity formsPlayer
//
// Ubiquity formsPlayer is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the
// Free Software Foundation; either version 3 of the License, or (at your
// option) any later version.
//
// Ubiquity formsPlayer is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License
// along with Ubiquity formsPlayer If not, see <http://www.gnu.org/licenses/>.
//	
//
//   Purpose: implementation of CImplSwitch.
//   $Id$


#include "stdafx.h"
#include "switch.h"
#include "switchUI.h"
#include "case.h"

CImplSwitch::CImplSwitch(CXFormsElementSwitch* pElement)
	: CImplSingleNodeBinding(static_cast<CXFormsElementSingleNodeBinding*>(pElement))
	,m_pCurrentCase(0)
{
	m_sRef = L".";
}

CImplSwitch::~CImplSwitch()
{
	// Delete any cases left undeleted.
	while (!m_Cases.IsEmpty())
	{
		try
		{
			CImplCase* pCase = m_Cases.GetHead();
			m_Cases.RemoveHead();
			pCase->m_pSwitch = 0;
			pCase->RequestDeleteAtEarliestConvenience();
		}
		catch(...){ASSERT(0);}

	}
}

void CImplSwitch::AddItem(CImplCase* pCase)
{
	m_Cases.AddTail(pCase);
}

void CImplSwitch::removeCaseReference(CImplCase * pCase)
{
	POSITION pos = m_Cases.Find(pCase);
	if(pos)
	{
		m_Cases.RemoveAt(pos);
	}
}

HRESULT CImplSwitch::SelectInitialCase()
{
	HRESULT hr = S_FALSE;
	//find the selectedCase.
	//	Don't bother if m_Cases is empty
	if(!m_Cases.IsEmpty())
	{
		CImplCase * pCaseInHand = NULL;
		POSITION pos;

		
		CComBSTR sTrue(L"true");
		bool bDoneOnce = false;
		bool bFoundSelected = false;
		
		bool bStrawkcab = IsWithinRepeat(this);
		if(bStrawkcab)
			pos = m_Cases.GetTailPosition();
		else
			pos = m_Cases.GetHeadPosition();
		CImplCase * pFirstCase = 0;
		m_pCurrentCase = 0;
		while(pos)
		{
			pCaseInHand = bStrawkcab?m_Cases.GetPrev(pos):m_Cases.GetNext(pos);
			if(!bFoundSelected && pCaseInHand->m_sSelected && wcscmp(pCaseInHand->m_sSelected,sTrue)==0)
			{
				m_pCurrentCase = pCaseInHand;
				bFoundSelected = true;
			}
			else
			{
				if(bDoneOnce)
					pCaseInHand->deselect();
				else
				{
					pFirstCase = pCaseInHand;
					bDoneOnce = true;
				}

			}
		}
		sTrue.Empty();
		if(!m_pCurrentCase)
		{
			//if none have evaluated to true, select the first
			// as default.  
			m_pCurrentCase = pFirstCase;
		}
		else if(pFirstCase && m_pCurrentCase != pFirstCase)
		{
			pFirstCase->deselect();
		}

		if(m_pCurrentCase)
		{
			m_pCurrentCase->select();
			CComBSTR sCurrentId = m_pCurrentCase->m_sId;
			m_pXFormsElement->put_value(sCurrentId);
		}
		hr = S_OK;
	}
	return hr;
}

HRESULT CImplSwitch::init(CImpl * pParent)
{
	HRESULT hr = S_OK;
	hr = __super::init(pParent);
	if(SUCCEEDED(hr))
	{
		hr = SelectInitialCase();
	}
	

	return hr;
}

HRESULT CImplSwitch::doInitialize()
{
	HRESULT hr = S_FALSE;
	
	if(m_bInParentContext)
	{
		CFormControl * pParentFC = dynamic_cast<CFormControl*>(m_pParentImpl);
		if(pParentFC && pParentFC->InitializeInProgress())
		{
			hr = __super::doInitialize();
			if(SUCCEEDED(hr) && !m_pCurrentCase)
				hr = SelectInitialCase();
		}
	}
	else
	{
		hr = __super::doInitialize();
		if(SUCCEEDED(hr) && !m_pCurrentCase)
			hr = SelectInitialCase();
	}
	return hr;
}

HRESULT CImplSwitch::toggle(CImplCase* pCase)
{
	//pCase is the Case to which one wishes to switch.
	//There is always one case switched on.

	HRESULT hr = S_OK;

	if (pCase &&  m_pCurrentCase != pCase)
	{
		if (m_pCurrentCase)
		{
			m_pCurrentCase->deselect();
		}
		m_pCurrentCase = pCase;

		// Bug 487 - Have moved the event after the refresh as trying to use the 
		// event to setfocus causes a javascript error. Have check the spec it states that
		// the event fires when "becoming selected" which we believe to be valid here.
		m_pCurrentCase->select();
	}
	else
	{
		//no new case was asked for, do nothing.
		return S_FALSE;
	}
	return hr;
}

HRESULT CImplSwitch::refresh()
{
	HRESULT hr = S_OK;

	POSITION pos = m_ReliantControls.GetHeadPosition();
	while(pos)
	{
		if(FAILED(m_ReliantControls.GetNext(pos)->refresh()))
			return E_FAIL;
	}
	
	FireStateEvents();

	return hr;
}

HRESULT CImplSwitch::AddChild(CImpl *pImpl)
{
	HRESULT hr = S_OK;

	if(!m_pParentImpl)
		m_pXFormsElement->ResolveEnclosingBinding();
	// Bug 465 - If the child is a xf:case then we add it to the xf:switch
	// other we have a invalid doc but this is what it did originally.
	CImplCase * pCase = dynamic_cast<CImplCase *>(pImpl);
	if(pCase) {
		hr = __super::AddChild(pImpl);
		AddItem(pCase);
		pCase->m_pSwitch = this;
	} else {
		hr = __super::AddChild(pImpl);

		/*		//You can't properly be the child of a switch.
		//Be the child of what is above it.
		pImpl->m_pParentImpl = m_pParentImpl;
		if(m_pParentImpl)
			hr = m_pParentImpl->AddChild(pImpl);
*/	}

	return hr;
}
